home *** CD-ROM | disk | FTP | other *** search
- /*
- * $RCSfile: lock.c,v $
- * $Revision: 1.1.1.1 $
- * $Date: 1996/05/04 21:55:26 $
- */
- /**********************************************************************
- * EXODUS Database Toolkit Software
- * Copyright (c) 1991 Computer Sciences Department, University of
- * Wisconsin -- Madison
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
- * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
- * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
- * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * The EXODUS Project Group requests users of this software to return
- * any improvements or extensions that they make to:
- *
- * EXODUS Project Group
- * c/o David J. DeWitt and Michael J. Carey
- * Computer Sciences Department
- * University of Wisconsin -- Madison
- * Madison, WI 53706
- *
- * or exodus@cs.wisc.edu
- *
- * In addition, the EXODUS Project Group requests that users grant the
- * Computer Sciences Department rights to redistribute these changes.
- **********************************************************************/
- #include "sysdefs.h"
- #include "ess.h"
- #include "checking.h"
- #include "trace.h"
- #include "error.h"
- #include "io.h"
- #include "list.h"
- #include "object.h"
- #include "tid.h"
- #include "lock.h"
- #include "page.h"
- #include "bf.h"
- #include "lm.h"
- #include "chunk.h"
- #include "bf_extfuncs.h"
- #include "bf_globals.h"
- #include "serverinfo.h"
- #include "sm_state.h"
- #include "trans.h"
- #include "trans_globals.h"
- #include "cc_macro.h"
- #include "lm_extfuncs.h"
- #include "lm_intfuncs.h"
- #include "lock_globals.h"
- #include "sm_globals.h"
-
- #ifdef LM_TRACE
- #undef LM_TRACE
- #define LM_TRACE(x) printf x
- #else
- #define LM_TRACE(x)
- #endif
-
-
-
- static int releaseQueueLen = 0;
- static void LM_UnlockPid(PID* pid, PAGEHASH* pageHash);
-
- typedef struct {
- PID pid;
- PAGEHASH* pageHash;
- LOCKMODE mode;
- int next;
- } PIDLock;
-
- static PIDLock lockPool[LM_RELEASELIMIT+1];
-
- static int freeList = 0;
- static int releaseQueue = -1;
- static int initialized = FALSE;
-
- static int lockCaching = 1;
-
-
- static void LM_Initialize()
- {
- int i;
- for (i = 0; i < 8; i++)
- lockPool[i].next = i+1;
- lockPool[7].next = -1;
-
- freeList = 0;
- initialized = TRUE;
- }
-
-
-
- void LM_PrintQueue()
- {
- register int p = releaseQueue;
- printf("Queue = ");
- for ( ; p >= 0; p = lockPool[p].next) {
- printf(" [%d]", lockPool[p].pid.page);
- }
- printf("\n");
- }
-
-
- lm_LockFile(FID* fid, LOCKMODE lockMode)
- {
- if (rpc_LockFile(fid, &lockMode)) return esmFAILURE;
-
- return esmNOERROR;
- }
-
-
-
- lm_LockPage(const PID* pid, PAGEHASH* pageHash, LOCKMODE lockMode, FID* fid)
- {
- if ( ! initialized) LM_Initialize();
-
- LM_TRACE(("Locking page %d", pid->page));
-
- /*
- * See if page lock is cached in releaseQueue
- */
- if (lockCaching) {
- register int p = releaseQueue;
- register int* pp = &releaseQueue;
- for ( ; p>=0 && ! PIDEQ(lockPool[p].pid, *pid);
- pp = & lockPool[p].next, p = lockPool[p].next) ;
-
- if (p < 0) {
- LM_TRACE(("(miss) \n"));
- }
- else {
- /*
- * Page lock is in releaseQueue --- see if need to upgrade lock
- */
- LOCKMODE suprMode = LM_Supremum[lockPool[p].mode][lockMode];
- if (suprMode != lockPool[p].mode) {
- /* call server to upgrade lock */
- if (rpc_LockPage(pid, PPAGE_TYPE(pageHash), &suprMode, fid))
- return esmFAILURE;
- }
- lockPool[p].mode = suprMode;
-
- /*
- * Unlock node from releaseQueue ---
- * i.e. take out from cache
- */
- SET_PAGEHASHLOCK(pageHash, suprMode);
- *pp = lockPool[p].next;
- lockPool[p].next = freeList;
- freeList = p;
- releaseQueueLen--;
-
- LM_TRACE(("(hit) \n"));
-
- return esmNOERROR;
- }
- }
-
- /*
- * Call server to lock page
- */
- if (rpc_LockPage(pid, PPAGE_TYPE(pageHash), &lockMode, fid))
- return esmFAILURE;
- pageHash->releaseCnt = 0;
- pageHash->releaseLimit = LM_RELEASELIMIT;
-
- SET_PAGEHASHLOCK(pageHash, lockMode);
-
- return esmNOERROR;
- }
-
-
-
- void lm_UnlockPage(PID* pid, PAGEHASH* pageHash)
- {
- register int p;
- LOCKMODE mode;
-
- if ( ! lockCaching) {
- LM_UnlockPid(pid, pageHash);
- return;
- }
-
- LM_TRACE(("Unlocking page %d\n", pid->page));
-
- if ( ! initialized) LM_Initialize();
-
- if ( ! (pageHash->flags & UNLOCKABLE_PAGE)) {
- printf("Trying to release non-unlockable locks\n");
- exit(-1);
- }
-
- #ifdef DEBUG
- for (p = releaseQueue; p >= 0; p = lockPool[p].next) {
- if (PIDEQ(lockPool[p].pid, *pid)) {
- printf("Page %d was unlocked\n", pid->page);
- LM_PrintQueue();
- exit(-1);
- }
- }
- #endif
-
- GET_PAGEHASHLOCK(pageHash, mode);
- SET_PAGEHASHLOCK(pageHash, NL);
-
- if (++pageHash->releaseCnt >= pageHash->releaseLimit) {
- /*
- * Reached pageHash->releaseLimit of this lock.
- */
- int serverReleaseLimit = 0;
- if (rpc_CheckPage(pid, pageHash->releaseLimit, &serverReleaseLimit))
- return;
- if (serverReleaseLimit == 0) {
- /*
- * Another transaction is waiting
- */
- LM_TRACE(("Another xact is waiting ... unlocking page %d\n",
- pid->page));
- LM_UnlockPid(pid, pageHash);
- return;
- }
- LM_TRACE(("ReleaseLimit for page %d changed to %d\n",
- pid->page, serverReleaseLimit));
- pageHash->releaseLimit = serverReleaseLimit;
- pageHash->releaseCnt = 0;
- }
-
- /* add lock to rear of release queue */
- p = freeList; /* allocate a node */
- SM_ASSERT(LEVEL_3, (p >= 0 && p < 8));
- freeList = lockPool[p].next;
- SM_ASSERT(LEVEL_3, (freeList == -1 || (freeList >= 0 && freeList < 8)));
-
- lockPool[p].pid = *pid;
- lockPool[p].pageHash = pageHash;
- lockPool[p].mode = mode;
- lockPool[p].next = releaseQueue;
- releaseQueue = p;
-
- if (releaseQueueLen++ >= LM_RELEASELIMIT) {
- int* pp = 0;
- releaseQueueLen = LM_RELEASELIMIT;
- LM_TRACE(("releaseQueueLen = %d, Limit = %d\n", releaseQueueLen,
- LM_RELEASELIMIT));
-
- for ( ; lockPool[p].next >= 0;
- pp = & lockPool[p].next, p = lockPool[p].next) ;
- *pp = -1;
- LM_UnlockPid(& lockPool[p].pid, lockPool[p].pageHash);
-
- lockPool[p].next = freeList;
- freeList = p;
- }
- }
-
-
-
-
- void lm_InvalidateAllLocks()
- {
- PID pids[sizeof(lockPool) / sizeof(lockPool[0])];
- int p;
- int cnt;
-
- LM_TRACE(("Releasing all locks\n"));
-
- for (p = releaseQueue, cnt = 0; p >= 0; p = lockPool[p].next) {
- pids[cnt++] = lockPool[p].pid;
- }
-
- for (p = cnt - 1; p >= 0; p--) {
- LM_TRACE(("Releasing lock on page page %d \n", pids[p].page));
- lm_InvalidateLock(& pids[p] );
- }
- }
-
- lm_IsLockCached(const PID* pid)
- {
- for (register p = releaseQueue;
- p >= 0 && ! PIDEQ(lockPool[p].pid, *pid); p = lockPool[p].next);
-
- return p >= 0;
- }
-
- void lm_ClearLockCache()
- {
- int pp;
- for (register p = releaseQueue; p >= 0; p = pp) {
- pp = lockPool[p].next;
- lockPool[p].next = freeList;
- freeList = p;
- }
- releaseQueueLen = 0;
- releaseQueue = -1;
- }
-
-
- void lm_InvalidateLock(const PID* pid)
- {
- register int p = releaseQueue;
- register int* pp = &releaseQueue;
-
- for ( ; p >= 0 && ! PIDEQ(lockPool[p].pid, *pid);
- pp = & lockPool[p].next, p = lockPool[p].next) ;
- if (p >= 0) {
- *pp = lockPool[p].next;
- releaseQueueLen--;
- lockPool[p].next = freeList;
- freeList = p;
- bf_RemoveFromBufGroups(lockPool[p].pageHash);
- LM_UnlockPid(& lockPool[p].pid, lockPool[p].pageHash);
- }
- }
-
-
- static void LM_UnlockPid(PID* pid, PAGEHASH* pageHash)
- {
- /*
- * Invalidate the local copy of the page, flushing it to
- * the server if the page is dirty.
- *
- * Do not leave the page in the hash table for possible reclaims
- * (for now, reclaims are done only on SLOTTED pages).
- * (remove == TRUE, forceToServer == TRUE)
- *
- * NB: we might have been called from bf_InvalidatePage(), but
- * if so, it will have removed the page hash from the hash table
- * so the recursive call will simply return.
- */
- bf_RemoveFromBufGroups(pageHash);
- bf_InvalidatePage(pageHash, TRUE, TRUE);
-
- /*
- * release lock on the server
- */
- LM_TRACE(("Unlocking page %d at server\n", pid->page));
-
- if (rpc_UnlockPage(pid)) {
- SM_ERROR(TYPE_WARNING, sm_errno);
- }
- }
-